package com.ccteam.admin.viewmodels.music

import android.app.Application
import android.net.Uri
import androidx.lifecycle.*
import com.ccteam.admin.core.TaglibParser
import com.ccteam.admin.repositories.MusicAdminRepository
import com.ccteam.admin.utils.ErrorMessage
import com.ccteam.admin.utils.Event
import com.ccteam.admin.utils.LoadMessage
import com.ccteam.admin.view.bean.SelectInfoResult
import com.ccteam.admin.vo.Resource
import com.ccteam.model.music.MusicDTO
import com.ccteam.model.music.MusicDetailVO
import com.ccteam.model.music.MusicInfoNoIdDTO
import com.ccteam.network.ApiError
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import java.io.FileNotFoundException
import javax.inject.Inject

/**
 * @author Xiaoc
 * @since 2021/4/20
 */
@HiltViewModel
class MusicAddViewModel @Inject constructor(
    application: Application,
    private val taglibParser: TaglibParser,
    private val musicRepository: MusicAdminRepository,
    private val savedStateHandle: SavedStateHandle
): AndroidViewModel(application) {

    private val _enableAddButton = MediatorLiveData<Boolean>()
    val enableAddButton: LiveData<Boolean> get() = _enableAddButton

    private val musicNameSuccess = MutableLiveData(false)
    private val durationSuccess = MutableLiveData(false)
    private val songYearSuccess = MutableLiveData(false)
    private val trackSuccess = MutableLiveData(false)
    private val artistsSuccess = MutableLiveData(false)

    private val _selectArtistList = MutableLiveData<MutableList<SelectInfoResult>>(mutableListOf())
    val selectArtistList: LiveData<MutableList<SelectInfoResult>> get() = _selectArtistList

    private val _editMusicInfo = MutableLiveData<MusicEditInfo>()
    val editMusicInfo: LiveData<MusicEditInfo> get() = _editMusicInfo

    private val _addLoadMessage = MutableLiveData<Event<LoadMessage>>()
    val addLoadMessage: LiveData<Event<LoadMessage>> get() = _addLoadMessage

    init {
        _enableAddButton.addSource(musicNameSuccess){
            _enableAddButton.value = it && durationSuccess.value == true &&
                    songYearSuccess.value == true && trackSuccess.value == true &&
                    artistsSuccess.value == true &&
                    _addLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }
        _enableAddButton.addSource(durationSuccess){
            _enableAddButton.value = it && musicNameSuccess.value == true &&
                    songYearSuccess.value == true && trackSuccess.value == true &&
                    artistsSuccess.value == true &&
                    _addLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }
        _enableAddButton.addSource(songYearSuccess){
            _enableAddButton.value = it && musicNameSuccess.value == true &&
                    durationSuccess.value == true && trackSuccess.value == true &&
                    artistsSuccess.value == true &&
                    _addLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }
        _enableAddButton.addSource(trackSuccess){
            _enableAddButton.value = it && durationSuccess.value == true &&
                    songYearSuccess.value == true && musicNameSuccess.value == true &&
                    artistsSuccess.value == true &&
                    _addLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }
        _enableAddButton.addSource(artistsSuccess){
            _enableAddButton.value = it && durationSuccess.value == true &&
                    songYearSuccess.value == true && trackSuccess.value == true &&
                    musicNameSuccess.value == true &&
                    _addLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }
        _enableAddButton.addSource(_addLoadMessage){
            _enableAddButton.value = it.peekContent() !is LoadMessage.Loading && durationSuccess.value == true &&
                    songYearSuccess.value == true && trackSuccess.value == true &&
                    musicNameSuccess.value == true
        }

        _editMusicInfo.value = MusicEditInfo(
            albumName = savedStateHandle["albumName"]
        )
    }

    /**
     * 添加已选择的歌手内容
     */
    fun addSelectArtist(artistInfo: SelectInfoResult){
        // 如果已选择中已包含了选择的内容，则不做其他处理
        if(_selectArtistList.value?.contains(artistInfo) == true){
            return
        }
        _selectArtistList.value?.add(artistInfo)
        _selectArtistList.value = _selectArtistList.value

        setArtistsSuccess(true)
    }

    /**
     * 取消已选择的歌手
     */
    fun removeSelectArtist(artistInfo: SelectInfoResult){
        _selectArtistList.value?.remove(artistInfo)

        val newList = _selectArtistList.value?.map {
            it.copy()
        }?.toMutableList() ?: mutableListOf()
        _selectArtistList.value = newList

        setArtistsSuccess(!newList.isNullOrEmpty())
    }

    fun setMusicName(name: String){
        _editMusicInfo.value?.name = name
    }
    fun setMusicNameSuccess(success: Boolean){
        musicNameSuccess.value = success
    }

    fun setDuration(duration: String){
        _editMusicInfo.value?.duration = duration
    }
    fun setDurationSuccess(success: Boolean){
        durationSuccess.value = success
    }

    fun setSongYear(songYear: String){
        _editMusicInfo.value?.songYear = songYear
    }
    fun setSongYearSuccess(success: Boolean){
        songYearSuccess.value = success
    }

    fun setTrack(track: String){
        _editMusicInfo.value?.track = track
    }
    fun setTrackSuccess(success: Boolean){
        trackSuccess.value = success
    }

    fun setLrc(lrc: String){
        _editMusicInfo.value?.lrc = lrc
    }

    fun setArtistsSuccess(success: Boolean){
        artistsSuccess.value = success
    }

    fun addMusic(){
        if(_editMusicInfo.value == null){
            _addLoadMessage.value = Event(LoadMessage.Error(ErrorMessage(ApiError.unknownCode,"新增数据为空")))
            return
        }

        if(_selectArtistList.value.isNullOrEmpty()){
            _addLoadMessage.value = Event(LoadMessage.Error(ErrorMessage(ApiError.unknownCode,"歌手列表为空，请选择")))
            return
        }

        _addLoadMessage.value = Event(LoadMessage.Loading)
        viewModelScope.launch {
            val artistList = _selectArtistList.value!!.map {
                it.selectId
            }
            val artistNameBuilder = StringBuilder()

            _selectArtistList.value!!.forEach {
                artistNameBuilder.append("${it.selectTitle}/")
            }
            // 去掉歌手字符串中最后的 "/"
            artistNameBuilder.deleteAt(artistNameBuilder.length - 1)

            val result = musicRepository.addMusicInfo(
                _editMusicInfo.value!!.toAddMusicInfoDto(artistNameBuilder.toString(),artistList)
            )
            if(result is Resource.Success){
                _addLoadMessage.value = Event(LoadMessage.Success)
            } else {
                _addLoadMessage.value = Event(LoadMessage.Error(ErrorMessage(ApiError.serverErrorCode,result.message)))
            }
        }
    }

    /**
     * 解析音乐媒体信息，更新新增的音乐内容
     */
    fun parseMusicInfo(uri: Uri){
        val application = getApplication<Application>()
        viewModelScope.launch {
            try {
                // 获取媒体信息
                val mediaInfoAsync = async(Dispatchers.IO){
                    application.contentResolver.openFileDescriptor(uri,"r")?.use {
                        taglibParser.getMediaTag(it.detachFd())
                    }
                }
                // 获取歌词
                val lrcAsync = async(Dispatchers.IO){
                    application.contentResolver.openFileDescriptor(uri,"r")?.use {
                        taglibParser.getLyricsByTaglib(it.detachFd())
                    }
                }
                val mediaInfo = mediaInfoAsync.await() ?: throw FileNotFoundException()
                val lrc = lrcAsync.await()

                _editMusicInfo.value = MusicEditInfo(
                    albumId = savedStateHandle["albumId"],albumName = savedStateHandle["albumName"],
                    duration = (mediaInfo.length * 1000).toString(),lrc = lrc,
                    name = mediaInfo.title,songYear = mediaInfo.year.toString(),track = mediaInfo.track.toString()
                )
            } catch (e: FileNotFoundException){
                _editMusicInfo.value = MusicEditInfo(
                    albumId = savedStateHandle["albumId"],albumName = savedStateHandle["albumName"]
                )
            }
        }
    }

}


data class MusicEditInfo(
    var id: String? = null,
    var albumId: String? = null,
    var albumName: String? = null,
    var artists: String? = null,
    var artistsId: List<String> = emptyList(),
    var duration: String? = null,
    var lrc: String? = null,
    var name: String? = null,
    var songYear: String? = null,
    var track: String? = null,
    var maxBitrate: String? = null
){
    companion object{
        fun toMusicEditInfo(musicVO: MusicDetailVO?): MusicEditInfo {
            return MusicEditInfo(
                musicVO?.id,
                musicVO?.albumId,
                musicVO?.albumName,
                musicVO?.artists,
                musicVO?.artistsId ?: emptyList(),
                musicVO?.duration.toString(),
                musicVO?.lrc,
                musicVO?.name,
                musicVO?.songYear,
                musicVO?.track.toString(),
                musicVO?.maxBitrate
            )
        }
    }

    fun toEditMusicInfoDto(artistsName: String,artistIds: List<String>): MusicDTO {
        return MusicDTO(
            id!!,
            albumId!!,
            albumName!!,
            artistsName,
            artistIds,
            duration!!,
            null,
            null,
            lrc,
            name!!,
            songYear!!,
            track?.toInt() ?: 0
        )
    }

    fun toAddMusicInfoDto(artistNames: String,artistList: List<String>): MusicInfoNoIdDTO {
        return MusicInfoNoIdDTO(
            albumId!!,
            albumName!!,
            artistNames,
            artistList,
            duration!!,
            lrc,
            name!!,
            songYear!!,
            track?.toInt() ?: 0
        )
    }
}